package br.com.ordersys.web;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import br.com.ordersys.framework.restlayer.RestLayerRequestAttributes;
/**
 * O objetivo deste filtro é processar o URI extraindo o ID do tenant, disponibiliza-lo como um atributo e fazer um forward com a URI verdadeira.
 * Desta forma podemos ter um URL específica por tenant, simplificando bookmark e todo o resto.
 * Se não for possível identificar o tenant desviamos para uma pagina de erro, pois o resto do sistema depende do atributo tenant
 * 
 * @author Cláudio Gualberto
 * 24/07/2013
 *
 */
@WebFilter(filterName="URLRewrite",value="/*")
public class TenantAwareURLRewriter implements Filter {
	private static final String STATIC_CONTENT_MARK = "/static_content/";
	
	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		
		Boolean done = (Boolean) req.getAttribute("url.tenant.rewrite.done");
		
		if(done == null){
			ProcessedURI tenantURI = extractTenantID(req);

			if(tenantURI.tenantID == null){ //se não conseguimos extrair o tenant da URI então desviamos para uma página de erro
				HttpServletResponse resp = (HttpServletResponse) response;
				
				if(req.getServletPath().endsWith("NoTenant.jsp")){// evita loop
					chain.doFilter(request, response);
				}else{
					((HttpServletResponse)response).sendRedirect("NoTenant.jsp?uri="+ resp.encodeRedirectURL(req.getRequestURI()));
				}
			}else{
				req.setAttribute("url.tenant.rewrite.done",Boolean.TRUE);// evita loop
				
				req.setAttribute(RestLayerRequestAttributes.TENANT_ID,tenantURI.tenantID); //registra o tenantID em um atribuito de request conhecido pelo resto da stack
				
				RequestDispatcher rd = request.getRequestDispatcher(tenantURI.fowardURI);
				
				rd.forward(request, response);
			}
		}else{
			chain.doFilter(request, response);
		}
	}
	
	/**
	 * Processa a URI, remove o tenantID e redefine a URI para um forward local.
	 * @return
	 */
	private ProcessedURI extractTenantID(HttpServletRequest req){
		//URI de exemplo: /OrderSys-web/tenantid/processos/xpto.jsp
		//URI reescrita:  /OrderSys-web/processos/xpto.jsp
		String uri = req.getRequestURI();
		ProcessedURI procURI = new ProcessedURI();
		
		Pattern p = Pattern.compile(req.getContextPath() + "(/\\w+)/.+", Pattern.DOTALL);
		
		Matcher m = p.matcher(uri);
		
		if(m.find()){
			procURI.tenantID = m.group(1).substring(1).toLowerCase();
			
			procURI.fowardURI = uri.substring(m.end(1));
			
			adjustStaticContentURI(procURI);
		}
		
		return procURI;
	}
	
	/**
		Procuro pela marcação de conteúdo estático para redefinirmos a URI para a pasta raiz da aplicação.
		Essa estratégia permite utilizar URIs do tipo REST para conteúdo dinamico com resources estáticos (.js, .css, etc)
		
		exemplo: um javascript carregado por um JSP que foi acessado com uma URL REST, ou seja:
			App/cadastro/cliente/10

		Se essa URL resolver para um JSP e esse JSP possuir um <script type="text/javascript" src='xpto.js'> do tipo relativo
		então o navegador vai tentar buscar o JS em 'App/cadastro/cliente/10/xpto.js'  quando na realidade queremos buscar em 'App/xpto.js' (considerando que o JS está na pasta root)
	 */
	private void adjustStaticContentURI(ProcessedURI procURI) {
		int staticMarkOnURI = procURI.fowardURI.indexOf(STATIC_CONTENT_MARK);
		
		if(staticMarkOnURI > -1){
			procURI.fowardURI = procURI.fowardURI.substring(staticMarkOnURI+STATIC_CONTENT_MARK.length()-1);
		}
	}

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
	}

	private class ProcessedURI{
		String fowardURI;
		String tenantID;
	}
}
